﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
using System.IO;
using System.Xml.Linq;
using System.Data;
using System.Data.Common;
using System.Collections;
using Microsoft.Practices.EnterpriseLibrary.Data;
using PBDesk.Utilities;
using System.Configuration;

namespace PBDesk.DAL
{
    class ParameterFactory
    {
        #region Constants

        const string SP_CONFIG_FILENAME = "StoredProcDets.xml";

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbCmd"></param>
        /// <param name="parameters"></param>
        internal static void CreateParameters(Database db, DbCommand dbCmd, Hashtable parameters)
        {
            string parameterName, parameterTypeInStr, parameterDirectionInStr;
            DbType parameterType;
            ParameterDirection parameterDirection;
            string spName = dbCmd.CommandText;

            //XDocument xDoc = GetSPFile(SP_CONFIG_FILENAME);
            XDocument xDoc = GetSPFile();

            if (xDoc != null && spName.IsNotNullAndNotEmpty())
            {
                var sp = from spElem in xDoc.Descendants("SP")
                         where spElem.Attribute("name").Value == spName
                         select spElem;

                foreach (var individualParameter in sp.Descendants("parameters").Descendants("parameter"))
                {
                    parameterName = individualParameter.Attributes("name").FirstOrDefault().Value;
                    if (parameterName == "ApplicationName")
                    {
                        AddApplicationNameParameter(ref db, ref dbCmd);
                    }
                    else
                    {
                        parameterTypeInStr = individualParameter.Attributes("type").FirstOrDefault().Value;
                        parameterDirectionInStr = individualParameter.Attributes("direction").FirstOrDefault().Value;

                        parameterDirection = GetParameterDirection(parameterDirectionInStr);
                        parameterType = GetDbType(parameterTypeInStr);
                        switch (parameterDirection)
                        {
                            case ParameterDirection.Input:
                                db.AddInParameter(dbCmd, parameterName, parameterType, parameters[parameterName]);
                                break;
                            case ParameterDirection.Output:
                                //db.AddOutParameter(dbCmd,parameterName,parameterType);
                                //todo
                                break;
                            case ParameterDirection.InputOutput:
                                //todo
                                break;

                        }
                    }
                }
            }
        }

        internal static void AddApplicationNameParameter(ref Database db, ref DbCommand dbCmd)
        {
            //db.AddInParameter(dbCmd, "ApplicationName", DbType.String, Membership.ApplicationName);
            db.AddInParameter(dbCmd, "ApplicationName", DbType.String, null);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="direction"></param>
        /// <returns></returns>
        internal static ParameterDirection GetParameterDirection(string direction)
        {
            ParameterDirection toReturn = ParameterDirection.Input;
            direction = direction ?? string.Empty;
            switch (direction.ToLower())
            {
                case "in":
                    toReturn = ParameterDirection.Input;
                    break;
                case "out":
                    toReturn = ParameterDirection.Output;
                    break;
                case "inout":
                    toReturn = ParameterDirection.InputOutput;
                    break;
                case "retvalue":
                    toReturn = ParameterDirection.ReturnValue;
                    break;
                default:
                    toReturn = ParameterDirection.Input;
                    break;
            }
            return toReturn;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="strType"></param>
        /// <returns></returns>
        internal static DbType GetDbType(string strType)
        {
            DbType toReturn = DbType.Object;

            switch (strType.ToLower())
            {
                case "string":
                    toReturn = DbType.String;
                    break;
                case "int32":
                    toReturn = DbType.Int32;
                    break;
                case "boolean":
                    toReturn = DbType.Boolean;
                    break;
                case "datetime":
                    toReturn = DbType.DateTime;
                    break;

            }
            return toReturn;
        }

        #region Private Supporting Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static XDocument GetSPFile(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName", "input fileName is null");
            }
            Assembly current = Assembly.GetExecutingAssembly();
            string currentAssemblyName = current.GetName().Name;
            Stream stream = current.GetManifestResourceStream(currentAssemblyName + "." + fileName);
            if (null == stream)
            {
                throw new ArgumentException("fileName", string.Format("Could not locate Embedded resource named {0} or is null or empty", fileName));
            }

            XmlTextReader xmlReader = new XmlTextReader(stream);
            XDocument xDoc = XDocument.Load(xmlReader);
            return xDoc;
        }

        private static XDocument GetSPFile()
        {
            string filePath = ConfigurationManager.AppSettings["PBDesk.DAL.StoredProcDetFilePath"];

            if (filePath.IsNullOrEmpty())
            {

                throw new InvalidOperationException("PBDesk.DAL.StoredProcDetFilePath not found in app settings section of your config file");
            }
            else
            {
                filePath = AppDomain.CurrentDomain.BaseDirectory + filePath;
                
            }
          
            XmlTextReader xmlReader = new XmlTextReader(filePath);
            XDocument xDoc = XDocument.Load(xmlReader);
            return xDoc;
        }




        #endregion
    }
}
